package com.szgz.platform.service.impl;

import com.szgz.platform.model.UserFile;
import com.szgz.platform.service.UserFileService;
import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Map;
import java.util.HashMap;

/**
 * 用户文件服务实现类
 */
@Service
public class UserFileServiceImpl implements UserFileService {
    
    private static final Logger logger = LoggerFactory.getLogger(UserFileServiceImpl.class);

    private String dockerCmd() {
        try {
            java.io.File linuxDocker = new java.io.File("/usr/bin/docker");
            if (linuxDocker.exists()) {
                return "/usr/bin/docker";
            }
        } catch (Exception ignored) {}
        return "docker"; // fall back to PATH
    }
    
    @Override
    public List<UserFile> getUserFiles(String userId) {
        return getUserFilesInDirectory(userId, "/home/coder/project");
    }
    
    @Override
    public List<UserFile> getUserFilesInDirectory(String userId, String directory) {
        List<UserFile> files = new ArrayList<>();
        
        try {
            // 检查容器是否运行
            if (!isContainerRunning("ide-" + userId)) {
                logger.warn("Container not running for user: {}", userId);
                return files;
            }
            
            // 使用 docker exec 命令列出目录内容
            ProcessBuilder pb = new ProcessBuilder(
                dockerCmd(), "exec", "ide-" + userId,
                "find", directory, "-maxdepth", "1", "-type", "f", "-o", "-type", "d"
            );
            
            Process process = pb.start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            
            String line;
            while ((line = reader.readLine()) != null) {
                if (!line.equals(directory)) { // 排除根目录本身
                    String fileName = Paths.get(line).getFileName().toString();
                    boolean isDirectory = isDirectoryInContainer(userId, line);
                    
                    UserFile file = new UserFile(userId, fileName, line, isDirectory);
                    
                    if (!isDirectory) {
                        // 获取文件大小和修改时间
                        setFileDetails(userId, file);
                    }
                    
                    files.add(file);
                }
            }
            
            process.waitFor();
            
        } catch (Exception e) {
            logger.error("Error getting files for user: {} in directory: {}", userId, directory, e);
        }
        
        return files;
    }
    
    @Override
    public List<UserFile> getUserProjects(String userId) {
        List<UserFile> allFiles = getUserFiles(userId);
        return allFiles.stream()
                .filter(this::isProjectFile)
                .collect(Collectors.toList());
    }
    
    @Override
    public String getFileContent(String userId, String filePath) {
        try {
            if (!isContainerRunning("ide-" + userId)) {
                logger.warn("Container not running for user: {}", userId);
                return null;
            }
            
            ProcessBuilder pb = new ProcessBuilder(
                dockerCmd(), "exec", "ide-" + userId,
                "cat", filePath
            );
            
            Process process = pb.start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            
            StringBuilder content = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                content.append(line).append("\n");
            }
            
            process.waitFor();
            return content.toString();
            
        } catch (Exception e) {
            logger.error("Error getting file content for user: {}, file: {}", userId, filePath, e);
            return null;
        }
    }
    
    @Override
    public List<UserFile> searchUserFiles(String userId, String query, String searchType) {
        List<UserFile> results = new ArrayList<>();
        
        try {
            if (!isContainerRunning("ide-" + userId)) {
                logger.warn("Container not running for user: {}", userId);
                return results;
            }
            
            ProcessBuilder pb;
            switch (searchType.toLowerCase()) {
                case "name":
                    pb = new ProcessBuilder(
                        dockerCmd(), "exec", "ide-" + userId,
                        "find", "/home/coder/project", "-name", "*" + query + "*"
                    );
                    break;
                case "content":
                    pb = new ProcessBuilder(
                        dockerCmd(), "exec", "ide-" + userId,
                        "grep", "-r", "-l", query, "/home/coder/project"
                    );
                    break;
                case "extension":
                    pb = new ProcessBuilder(
                        dockerCmd(), "exec", "ide-" + userId,
                        "find", "/home/coder/project", "-name", "*." + query
                    );
                    break;
                default:
                    pb = new ProcessBuilder(
                        dockerCmd(), "exec", "ide-" + userId,
                        "find", "/home/coder/project", "-name", "*" + query + "*"
                    );
            }
            
            Process process = pb.start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            
            String line;
            while ((line = reader.readLine()) != null) {
                String fileName = Paths.get(line).getFileName().toString();
                boolean isDirectory = isDirectoryInContainer(userId, line);
                
                UserFile file = new UserFile(userId, fileName, line, isDirectory);
                if (!isDirectory) {
                    setFileDetails(userId, file);
                }
                
                results.add(file);
            }
            
            process.waitFor();
            
        } catch (Exception e) {
            logger.error("Error searching files for user: {}, query: {}", userId, query, e);
        }
        
        return results;
    }
    
    @Override
    public UserFileStats getUserFileStats(String userId) {
        UserFileStats stats = new UserFileStats();
        List<UserFile> allFiles = getUserFiles(userId);
        
        for (UserFile file : allFiles) {
            if (file.isDirectory()) {
                stats.setTotalDirectories(stats.getTotalDirectories() + 1);
            } else {
                stats.setTotalFiles(stats.getTotalFiles() + 1);
                Long fileSize = file.getFileSize();
                if (fileSize != null) {
                    stats.setTotalSize(stats.getTotalSize() + fileSize);
                }
                
                String fileType = file.getFileType();
                if (fileType != null) {
                    switch (fileType) {
                        case "code":
                            stats.setCodeFiles(stats.getCodeFiles() + 1);
                            break;
                        case "document":
                            stats.setDocumentFiles(stats.getDocumentFiles() + 1);
                            break;
                        case "image":
                            stats.setImageFiles(stats.getImageFiles() + 1);
                            break;
                        default:
                            stats.setOtherFiles(stats.getOtherFiles() + 1);
                            break;
                    }
                }
            }
        }
        
        return stats;
    }

    @Override
    public String uploadFileToIde(String userId, MultipartFile file, String targetDirectory) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("File is empty");
        }
        String dir = (targetDirectory == null || targetDirectory.isBlank()) ? "/home/coder/project" : targetDirectory;
        try {
            if (!isContainerRunning("ide-" + userId)) {
                throw new IllegalStateException("IDE container not running for user " + userId);
            }
            // 保存到临时文件
            File temp = File.createTempFile("upload-", "-" + sanitizeFileName(file.getOriginalFilename()));
            try (FileOutputStream fos = new FileOutputStream(temp)) {
                fos.write(file.getBytes());
            }
            // 复制到容器
            ProcessBuilder cpPb = new ProcessBuilder(
                dockerCmd(), "cp", temp.getAbsolutePath(), "ide-" + userId + ":" + dir + "/" + sanitizeFileName(file.getOriginalFilename())
            );
            Process cp = cpPb.start();
            int exit = cp.waitFor();
            temp.delete();
            if (exit != 0) {
                throw new RuntimeException("docker cp failed with exit code " + exit);
            }
            return dir + "/" + sanitizeFileName(file.getOriginalFilename());
        } catch (Exception e) {
            logger.error("Failed to upload file to IDE for user {}: {}", userId, e.getMessage());
            throw new RuntimeException("Upload failed: " + e.getMessage(), e);
        }
    }

    @Override
    public List<String> uploadFilesToIde(String userId, List<MultipartFile> files, String targetDirectory) {
        List<String> results = new ArrayList<>();
        if (files == null || files.isEmpty()) return results;
        for (MultipartFile f : files) {
            try {
                results.add(uploadFileToIde(userId, f, targetDirectory));
            } catch (Exception e) {
                logger.error("Error uploading file: {}", f.getOriginalFilename(), e);
            }
        }
        return results;
    }

    @Override
    public List<String> uploadMultipleFilesToIde(String userId, List<MultipartFile> files, String targetDirectory) throws Exception {
        List<String> results = new ArrayList<>();
        if (files == null || files.isEmpty()) return results;
        for (MultipartFile f : files) {
            results.add(uploadFileToIde(userId, f, targetDirectory));
        }
        return results;
    }

    @Override
    public List<UserFileService.FileTreeNode> getUserFileTree(String userId, String rootDirectory) {
        List<UserFileService.FileTreeNode> tree = new ArrayList<>();
        
        try {
            logger.info("Starting file tree generation for user: {} in directory: {}", userId, rootDirectory);
            long startTime = System.currentTimeMillis();
            
            // 检查容器状态
            if (!isContainerRunning("ide-" + userId)) {
                logger.warn("Container not running for user: {}", userId);
                return tree;
            }
            
            // 首先检查目录是否存在（带超时）
            logger.info("Checking directory existence...");
            ProcessBuilder checkPb = new ProcessBuilder(
                dockerCmd(), "exec", "ide-" + userId,
                "test", "-d", rootDirectory
            );
            Process checkProcess = checkPb.start();
            
            // 设置超时：5秒
            if (!checkProcess.waitFor(5, java.util.concurrent.TimeUnit.SECONDS)) {
                logger.error("Directory check timeout for user: {}", userId);
                checkProcess.destroyForcibly();
                return tree;
            }
            
            int checkResult = checkProcess.exitValue();
            
            if (checkResult != 0) {
                logger.warn("Directory {} does not exist in container for user: {}", rootDirectory, userId);
                // 尝试创建目录（带超时）
                logger.info("Creating directory...");
                ProcessBuilder mkdirPb = new ProcessBuilder(
                    dockerCmd(), "exec", "ide-" + userId,
                    "mkdir", "-p", rootDirectory
                );
                Process mkdirProcess = mkdirPb.start();
                
                if (!mkdirProcess.waitFor(10, java.util.concurrent.TimeUnit.SECONDS)) {
                    logger.error("Directory creation timeout for user: {}", userId);
                    mkdirProcess.destroyForcibly();
                    return tree;
                }
                
                // 设置权限（带超时）
                logger.info("Setting permissions...");
                ProcessBuilder chownPb = new ProcessBuilder(
                    dockerCmd(), "exec", "ide-" + userId,
                    "chown", "-R", "coder:coder", rootDirectory
                );
                Process chownProcess = chownPb.start();
                
                if (!chownProcess.waitFor(10, java.util.concurrent.TimeUnit.SECONDS)) {
                    logger.error("Permission setting timeout for user: {}", userId);
                    chownProcess.destroyForcibly();
                    return tree;
                }
                
                logger.info("Created directory {} for user: {}", rootDirectory, userId);
            }
            
            // 使用 docker exec 命令递归列出目录内容（带超时）
            logger.info("Executing find command...");
            ProcessBuilder pb = new ProcessBuilder(
                dockerCmd(), "exec", "ide-" + userId,
                "find", rootDirectory, "-type", "f", "-o", "-type", "d"
            );
            
            Process process = pb.start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            
            List<String> allPaths = new ArrayList<>();
            String line;
            
            // 设置读取超时：15秒
            long readStartTime = System.currentTimeMillis();
            while ((line = reader.readLine()) != null) {
                if (System.currentTimeMillis() - readStartTime > 15000) {
                    logger.error("File listing timeout for user: {}", userId);
                    process.destroyForcibly();
                    return tree;
                }
                allPaths.add(line);
            }
            
            // 读取错误输出
            StringBuilder errorOutput = new StringBuilder();
            while ((line = errorReader.readLine()) != null) {
                errorOutput.append(line).append("\n");
            }
            
            // 等待进程完成（带超时）
            if (!process.waitFor(20, java.util.concurrent.TimeUnit.SECONDS)) {
                logger.error("Find command timeout for user: {}", userId);
                process.destroyForcibly();
                return tree;
            }
            
            int exitCode = process.exitValue();
            
            if (exitCode != 0) {
                logger.error("Docker exec command failed with exit code: {}, error: {}", exitCode, errorOutput.toString());
                return tree;
            }
            
            if (allPaths.isEmpty()) {
                logger.info("Directory {} is empty for user: {}", rootDirectory, userId);
                return tree;
            }
            
            logger.info("Found {} paths, building file tree...", allPaths.size());
            
            // 构建文件树（带文件信息，但使用快速方法）
            Map<String, UserFileService.FileTreeNode> pathToNode = new HashMap<>();
            
            for (String path : allPaths) {
                if (path.equals(rootDirectory)) {
                    continue; // 跳过根目录本身
                }
                
                String[] pathParts = path.substring(rootDirectory.length()).split("/");
                String currentPath = rootDirectory;
                
                for (int i = 1; i < pathParts.length; i++) {
                    String part = pathParts[i];
                    if (part.isEmpty()) continue;
                    
                    String parentPath = currentPath;
                    currentPath = currentPath + "/" + part;
                    
                    if (!pathToNode.containsKey(currentPath)) {
                        // 使用快速方法判断是否为目录（针对当前路径）
                        boolean isDir = isDirectoryQuick(userId, currentPath);
                        UserFileService.FileTreeNode node = new UserFileService.FileTreeNode(part, currentPath, isDir);
                        
                        // 快速获取文件信息（带超时控制）
                        if (!isDir) {
                            setFileTreeNodeDetailsQuick(userId, node);
                        }
                        
                        pathToNode.put(currentPath, node);
                        
                        // 添加到父节点
                        if (pathToNode.containsKey(parentPath)) {
                            pathToNode.get(parentPath).addChild(node);
                        } else if (parentPath.equals(rootDirectory)) {
                            tree.add(node);
                        }
                    }
                }
            }
            
            long endTime = System.currentTimeMillis();
            logger.info("Successfully built file tree for user: {} with {} nodes in {}ms", 
                       userId, tree.size(), (endTime - startTime));
            
        } catch (Exception e) {
            logger.error("Error getting file tree for user: {} in directory: {}", userId, rootDirectory, e);
        }
        
        return tree;
    }

    @Override
    public boolean saveFileContent(String userId, String filePath, String content) {
        try {
            if (!isContainerRunning("ide-" + userId)) {
                throw new IllegalStateException("IDE container not running for user " + userId);
            }

            // 将内容写入临时文件
            File temp = File.createTempFile("save-", ".tmp");
            try (FileOutputStream fos = new FileOutputStream(temp)) {
                fos.write(content.getBytes(java.nio.charset.StandardCharsets.UTF_8));
            }

            // docker cp 到目标路径
            ProcessBuilder cpPb = new ProcessBuilder(
                    dockerCmd(), "cp", temp.getAbsolutePath(), "ide-" + userId + ":" + filePath
            );
            Process cp = cpPb.start();
            int exit = cp.waitFor();
            temp.delete();
            if (exit != 0) {
                return false;
            }

            // 统一归属为 coder 用户，避免在 IDE 中因权限导致保存失败
            // 将文件属主设置为父目录的属主(uid:gid)，避免依赖具体用户名
            ProcessBuilder chownPb = new ProcessBuilder(
                    dockerCmd(), "exec", "--user", "0", "ide-" + userId,
                    "sh", "-lc",
                    "P=\"$(dirname '" + filePath + "')\"; UG=\"$(stat -c %u:%g \"$P\" 2>/dev/null || stat -f %u:%g \"$P\" 2>/dev/null || echo 1000:1000)\"; chown \"$UG\" '" + filePath + "' || true"
            );
            Process ch = chownPb.start();
            ch.waitFor();
            return true;
        } catch (Exception e) {
            logger.error("saveFileContent failed for user {}, path {}", userId, filePath, e);
            return false;
        }
    }

    @Override
    public boolean createFile(String userId, String filePath) {
        try {
            if (!isContainerRunning("ide-" + userId)) {
                throw new IllegalStateException("IDE container not running for user " + userId);
            }
            ProcessBuilder pb = new ProcessBuilder(
                    dockerCmd(), "exec", "--user", "0", "ide-" + userId,
                    "sh", "-lc",
                    "D=\"$(dirname '" + filePath + "')\"; mkdir -p \"$D\" && touch '" + filePath + "' && UG=\"$(stat -c %u:%g \"$D\" 2>/dev/null || stat -f %u:%g \"$D\" 2>/dev/null || echo 1000:1000)\" && chown \"$UG\" '" + filePath + "'"
            );
            Process p = pb.start();
            return p.waitFor() == 0;
        } catch (Exception e) {
            logger.error("createFile failed for user {}, path {}", userId, filePath, e);
            return false;
        }
    }

    @Override
    public boolean createDirectory(String userId, String dirPath) {
        try {
            if (!isContainerRunning("ide-" + userId)) {
                throw new IllegalStateException("IDE container not running for user " + userId);
            }
            ProcessBuilder pb = new ProcessBuilder(
                    dockerCmd(), "exec", "--user", "0", "ide-" + userId,
                    "sh", "-lc",
                    "mkdir -p '" + dirPath + "' && P=\"$(dirname '" + dirPath + "')\" && UG=\"$(stat -c %u:%g \"$P\" 2>/dev/null || stat -f %u:%g \"$P\" 2>/dev/null || echo 1000:1000)\" && chown -R \"$UG\" '" + dirPath + "'"
            );
            Process p = pb.start();
            return p.waitFor() == 0;
        } catch (Exception e) {
            logger.error("createDirectory failed for user {}, path {}", userId, dirPath, e);
            return false;
        }
    }

    @Override
    public boolean deletePath(String userId, String path, boolean recursive) {
        try {
            if (!isContainerRunning("ide-" + userId)) {
                throw new IllegalStateException("IDE container not running for user " + userId);
            }
            String cmd = recursive ? "rm -rf" : "rm -f";
            // 以 root 身份删除，避免因属主或权限不足导致失败
            ProcessBuilder pb = new ProcessBuilder(
                    dockerCmd(), "exec", "--user", "0", "ide-" + userId,
                    "sh", "-lc", cmd + " '" + path + "'"
            );
            Process p = pb.start();
            return p.waitFor() == 0;
        } catch (Exception e) {
            logger.error("deletePath failed for user {}, path {}", userId, path, e);
            return false;
        }
    }
    
    // 私有辅助方法
    
    private boolean isContainerRunning(String containerName) {
        try {
            ProcessBuilder pb = new ProcessBuilder(
                dockerCmd(), "ps", "--filter", "name=" + containerName, "--format", "{{.Names}}"
            );
            Process process = pb.start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            
            String line = reader.readLine();
            process.waitFor();
            
            return line != null && line.contains(containerName);
        } catch (Exception e) {
            logger.error("Error checking container status: {}", containerName, e);
            return false;
        }
    }
    
    private boolean isDirectoryInContainer(String userId, String path) {
        try {
            ProcessBuilder pb = new ProcessBuilder(
                dockerCmd(), "exec", "ide-" + userId,
                "test", "-d", path
            );
            Process process = pb.start();
            int exitCode = process.waitFor();
            return exitCode == 0;
        } catch (Exception e) {
            logger.error("Error checking if path is directory: {}", path, e);
            return false;
        }
    }
    
    private void setFileDetails(String userId, UserFile file) {
        try {
            // 获取文件大小
            ProcessBuilder sizePb = new ProcessBuilder(
                dockerCmd(), "exec", "ide-" + userId,
                "stat", "-c", "%s", file.getFilePath()
            );
            Process sizeProcess = sizePb.start();
            BufferedReader sizeReader = new BufferedReader(new InputStreamReader(sizeProcess.getInputStream()));
            String sizeLine = sizeReader.readLine();
            sizeProcess.waitFor();
            
            if (sizeLine != null) {
                file.setFileSize(Long.parseLong(sizeLine.trim()));
            }
            
            // 获取文件修改时间
            ProcessBuilder timePb = new ProcessBuilder(
                dockerCmd(), "exec", "ide-" + userId,
                "stat", "-c", "%Y", file.getFilePath()
            );
            Process timeProcess = timePb.start();
            BufferedReader timeReader = new BufferedReader(new InputStreamReader(timeProcess.getInputStream()));
            String timeLine = timeReader.readLine();
            timeProcess.waitFor();
            
            if (timeLine != null) {
                long timestamp = Long.parseLong(timeLine.trim());
                file.setLastModified(LocalDateTime.ofEpochSecond(timestamp, 0, java.time.ZoneOffset.UTC));
            }
            
            // 获取文件权限
            ProcessBuilder permPb = new ProcessBuilder(
                dockerCmd(), "exec", "ide-" + userId,
                "stat", "-c", "%a", file.getFilePath()
            );
            Process permProcess = permPb.start();
            BufferedReader permReader = new BufferedReader(new InputStreamReader(permProcess.getInputStream()));
            String permLine = permReader.readLine();
            permProcess.waitFor();
            
            if (permLine != null) {
                file.setPermissions(permLine.trim());
            }
            
            // 设置文件类型
            String fileName = file.getFileName();
            if (fileName != null && fileName.contains(".")) {
                String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
                file.setFileType(determineFileType(extension));
            } else {
                file.setFileType("unknown");
            }
            
        } catch (Exception e) {
            logger.error("Error setting file details for: {}", file.getFilePath(), e);
        }
    }

    private void setFileTreeNodeDetails(String userId, UserFileService.FileTreeNode node) {
        try {
            // 获取文件大小
            ProcessBuilder sizePb = new ProcessBuilder(
                dockerCmd(), "exec", "ide-" + userId,
                "stat", "-c", "%s", node.getPath()
            );
            Process sizeProcess = sizePb.start();
            BufferedReader sizeReader = new BufferedReader(new InputStreamReader(sizeProcess.getInputStream()));
            String sizeLine = sizeReader.readLine();
            sizeProcess.waitFor();
            
            if (sizeLine != null) {
                node.setSize(Long.parseLong(sizeLine.trim()));
            }
            
            // 获取文件修改时间
            ProcessBuilder timePb = new ProcessBuilder(
                dockerCmd(), "exec", "ide-" + userId,
                "stat", "-c", "%Y", node.getPath()
            );
            Process timeProcess = timePb.start();
            BufferedReader timeReader = new BufferedReader(new InputStreamReader(timeProcess.getInputStream()));
            String timeLine = timeReader.readLine();
            timeProcess.waitFor();
            
            if (timeLine != null) {
                long timestamp = Long.parseLong(timeLine.trim());
                node.setLastModified(LocalDateTime.ofEpochSecond(timestamp, 0, java.time.ZoneOffset.UTC));
            }
            
            // 设置文件类型
            String fileName = node.getName();
            if (fileName.contains(".")) {
                String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
                node.setFileType(determineFileType(extension));
            } else {
                node.setFileType("unknown");
            }
            
        } catch (Exception e) {
            logger.error("Error setting file tree node details for: {}", node.getPath(), e);
        }
    }
    
    // 检查是否为项目文件
    private boolean isProjectFile(UserFile file) {
        String fileName = file.getFileName();
        if (fileName == null) return false;
        
        return fileName.equals("pom.xml") || 
               fileName.equals("package.json") || 
               fileName.equals("requirements.txt") ||
               fileName.equals("build.gradle") ||
               fileName.equals("Cargo.toml") ||
               fileName.equals("go.mod") ||
               fileName.equals("Gemfile") ||
               fileName.equals("composer.json") ||
               fileName.equals("Dockerfile") ||
               fileName.equals("docker-compose.yml");
    }
    
    private String determineFileType(String extension) {
        if (extension == null || extension.isEmpty()) {
            return "unknown";
        }
        
        String ext = extension.toLowerCase();
        
        // 代码文件
        if (ext.matches("(java|py|js|ts|html|css|xml|json|sql|sh|bat|ps1|cpp|c|h|cs|php|rb|go|rs|swift|kt|scala|r|m|pl|lua|dart|vue|jsx|tsx)")) {
            return "code";
        }
        
        // 文档文件
        if (ext.matches("(txt|md|doc|docx|pdf|rtf|odt|pages)")) {
            return "document";
        }
        
        // 图片文件
        if (ext.matches("(jpg|jpeg|png|gif|bmp|svg|webp|ico|tiff)")) {
            return "image";
        }
        
        // 视频文件
        if (ext.matches("(mp4|avi|mov|wmv|flv|webm|mkv|m4v)")) {
            return "video";
        }
        
        // 音频文件
        if (ext.matches("(mp3|wav|flac|aac|ogg|wma|m4a)")) {
            return "audio";
        }
        
        // 压缩文件
        if (ext.matches("(zip|rar|7z|tar|gz|bz2|xz)")) {
            return "archive";
        }
        
        // 数据文件
        if (ext.matches("(csv|excel|xls|xlsx|db|sqlite|json|yaml|yml|toml|ini|cfg|conf)")) {
            return "data";
        }
        
        return "other";
    }
    
    private String sanitizeFileName(String name) {
        if (name == null) return "uploaded-file";
        return name.replaceAll("[\\\\/]+", "-");
    }
    
    // 快速判断是否为目录（带超时控制）
    private boolean isDirectoryQuick(String userId, String path) {
        try {
            ProcessBuilder pb = new ProcessBuilder(
                dockerCmd(), "exec", "ide-" + userId,
                "test", "-d", path
            );
            Process process = pb.start();
            
            // 3秒超时
            if (!process.waitFor(3, java.util.concurrent.TimeUnit.SECONDS)) {
                logger.warn("Directory check timeout for path: {}", path);
                process.destroyForcibly();
                return false; // 超时默认返回 false
            }
            
            return process.exitValue() == 0;
        } catch (Exception e) {
            logger.error("Error checking if path is directory: {}", path, e);
            return false;
        }
    }
    
    // 快速获取文件树节点详情（带超时控制）
    private void setFileTreeNodeDetailsQuick(String userId, UserFileService.FileTreeNode node) {
        try {
            // 获取文件大小（3秒超时）
            ProcessBuilder sizePb = new ProcessBuilder(
                dockerCmd(), "exec", "ide-" + userId,
                "stat", "-c", "%s", node.getPath()
            );
            Process sizeProcess = sizePb.start();
            
            if (sizeProcess.waitFor(3, java.util.concurrent.TimeUnit.SECONDS)) {
                BufferedReader sizeReader = new BufferedReader(new InputStreamReader(sizeProcess.getInputStream()));
                String sizeLine = sizeReader.readLine();
                if (sizeLine != null) {
                    try {
                        node.setSize(Long.parseLong(sizeLine.trim()));
                    } catch (NumberFormatException e) {
                        logger.warn("Invalid file size for: {}", node.getPath());
                    }
                }
            } else {
                logger.warn("File size check timeout for: {}", node.getPath());
                sizeProcess.destroyForcibly();
            }
            
            // 获取文件修改时间（3秒超时）
            ProcessBuilder timePb = new ProcessBuilder(
                dockerCmd(), "exec", "ide-" + userId,
                "stat", "-c", "%Y", node.getPath()
            );
            Process timeProcess = timePb.start();
            
            if (timeProcess.waitFor(3, java.util.concurrent.TimeUnit.SECONDS)) {
                BufferedReader timeReader = new BufferedReader(new InputStreamReader(timeProcess.getInputStream()));
                String timeLine = timeReader.readLine();
                if (timeLine != null) {
                    try {
                        long timestamp = Long.parseLong(timeLine.trim());
                        node.setLastModified(LocalDateTime.ofEpochSecond(timestamp, 0, java.time.ZoneOffset.UTC));
                    } catch (NumberFormatException e) {
                        logger.warn("Invalid timestamp for: {}", node.getPath());
                    }
                }
            } else {
                logger.warn("File time check timeout for: {}", node.getPath());
                timeProcess.destroyForcibly();
            }
            
            // 设置文件类型（基于文件名，不需要 Docker 命令）
            String fileName = node.getName();
            if (fileName != null && fileName.contains(".")) {
                String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
                node.setFileType(determineFileType(extension));
            } else {
                node.setFileType("unknown");
            }
            
        } catch (Exception e) {
            logger.error("Error setting file tree node details for: {}", node.getPath(), e);
        }
    }
} 